package com.ferry.common.util;

import com.sun.management.HotSpotDiagnosticMXBean;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Created by daiyong
 */
public class JvmUtil {

	private JvmUtil(){}

	/**
	 * 获取线程堆栈
	 * @return
	 * @throws Exception
	 */
	public static List<String> jStack() throws Exception {
		List<String> stackList = new LinkedList<>();
		Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
		for (Map.Entry<Thread, StackTraceElement[]> entry : allStackTraces.entrySet()) {
			Thread thread = entry.getKey();
			StackTraceElement[] stackTraces = entry.getValue();

			stackList.add(
					String.format(
							"\"%s\" tid=%s isDaemon=%s priority=%s" + "\r\n",
							thread.getName(),
							thread.getId(),
							thread.isDaemon(),
							thread.getPriority()
					)
			);

			stackList.add("java.lang.Thread.State: " + thread.getState() + "\r\n");

			if (stackTraces != null) {
				for (StackTraceElement s : stackTraces) {
					stackList.add("    " + s.toString() + "\r\n");
				}
			}
		}
		return stackList;
	}

	public static List<String> memoryUsage() throws Exception {
		MemoryUsage heapMemoryUsage = MXBeanHolder.memoryMxBean.getHeapMemoryUsage();
		MemoryUsage nonHeapMemoryUsage = MXBeanHolder.memoryMxBean.getNonHeapMemoryUsage();

		List<String> memoryUsageList = new LinkedList<>();
		memoryUsageList.add("Heap Memory Usage: " + heapMemoryUsage.toString() + "\r\n");
		memoryUsageList.add("NonHeap Memory Usage: " + nonHeapMemoryUsage.toString() + "\r\n");

		return memoryUsageList;
	}

	public static double memoryUsed() throws Exception {
		MemoryUsage heapMemoryUsage = MXBeanHolder.memoryMxBean.getHeapMemoryUsage();
		return (double) (heapMemoryUsage.getUsed()) / heapMemoryUsage.getMax();
	}

	@SuppressWarnings("all")
	public static void jMap(String outputFile, boolean live) throws Exception {
		File file = new File(outputFile);
		if (file.exists()) {
			file.delete();
		}
		MXBeanHolder.hotSpotDiagnosticMxBean.dumpHeap(outputFile, live);
	}

	private static class MXBeanHolder {
		static final MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();
		static final HotSpotDiagnosticMXBean hotSpotDiagnosticMxBean =
				ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
	}

}
